`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    13:24:11 05/19/2014 
// Design Name: 
// Module Name:    MontProd 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
// 
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
`define BITS 16

module MontProd(
	input 	clk,
	input		start,
	input 	[`BITS - 1:0]	A,
	input 	[`BITS - 1:0]	B,
	input 	[`BITS - 1:0]	M,
	output	reg done ,
	output 	reg [`BITS - 1:0]	result
);

	//****** Parameters *****************
	parameter	RESET			=  7'b0000001,
					INIT			=	7'b0000010,
					CHECK_CNT	=	7'b0000100,
					CALC_Q		=	7'b0001000,
					EVAL_S		=	7'b0010000,
					UPD_CNT		=	7'b0100000,
					DONE			=	7'b1000000;
					
					
	reg [6:0]	State; 
	reg [6:0] 	NextState;
	reg [`BITS - 1:0]	S	= 0;
	reg [`BITS - 1:0]	count = 0;	 
	reg [`BITS - 1:0]	q	= 0;	
	reg start_pulse;	

	//Update state
	always @(posedge clk)
	begin
		if(start == 0)	
			State	<= RESET;
		else
			State <= NextState;
	end

	//Next state logic
	always @(*)
	begin
		case (State)
			RESET: 		begin
								NextState	= INIT;
							end
						
			INIT:			begin
								NextState	= CHECK_CNT;
							end	
							
			CHECK_CNT:	begin
								if(count == `BITS)
									NextState = DONE;
								else
									NextState = CALC_Q;		
							end
							
			CALC_Q:		begin
								NextState = EVAL_S;
							end					
			
			EVAL_S:		begin
								NextState = UPD_CNT;
							end
			
			UPD_CNT: 	begin
								NextState = CHECK_CNT;
							end
			
			DONE:			begin 
								NextState = RESET;
							end
			
			default:		NextState = RESET;			
		endcase
	end
	
	//Output Logic

	always @(posedge clk)
	begin
	/*	done 		= done;
		S			= S;
		count 	= count;	 
		q			= q;
		result	= result;	
	*/	
		case (State)
			RESET:	begin
							done <= 0;
							result <= 0;
						end								
			
			INIT:		begin
							S	<= 0;
							count <= 0;	 
							q	<= 0;
							done <= 0;
						end	
			
			CHECK_CNT:begin
							done <= 0;
						 end	

			//q	=	(S + (B[count] * A)) % 2;
			CALC_Q:	begin
							q    <= (S + (B[count] * A)) % 2;
							done <= 0;
						end	
						/*begin
							if(B[count] == 0)
								q	=	S[0];
							else
								q = (S[0] ^ A[0]);	
						end							
						*/
			//S	=	(S + (q * M) + (B[count] * A)) / 2;
			EVAL_S:			begin
									S	  <= 	(S + (q * M) + (B[count] * A)) / 2;
									done <= 0;
								end	
						/*begin
							if(q == 0)
							begin
								if(B[count] == 0)
									S	=	S >> 2;
								else
									S = (S +  A) >> 2;	
							end		
							else
							begin
								if(B[count] == 0)
									S	=	(S +  M) >> 2;	
								else
									S = (S +  M + A) >> 2;	
							end										
						end
						*/										
			UPD_CNT: begin
							count <= count + 1;
							done  <= 0;
						end
			
			DONE:		begin 
							done   <= 1;
							result <= S;
						end
			
			default:	done <= 0;			
		endcase
	end
endmodule
